home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
PROGRAMM
/
PASCAL
/
0921.ZIP
/
MAZE.ARC
/
MAZE.PAS
Wrap
Pascal/Delphi Source File
|
1987-11-22
|
23KB
|
678 lines
PROGRAM maze(INPUT,OUTPUT);
{
This program builds a maze on your CRT. After the maze is built,
you may use the cursor keys to solve it. Press "Q" to quit or press
"S" to have the computer solve the maze. If the computer solves the
maze, you must press some key to exit. A different random number seed
will produce a different maze. Each maze has exactly one solution that
does not involve backtracking (passing through a doorway more than once).
Written by James L. Dean.
}
CONST
{ Columns and rows in maze. }
max_num_columns=159;
max_num_rows=99;
{ Color assignments. }
erase=2; { Wall must be positive }
wall=3; { Wall, passage, and path }
passage=0; { must be different. Wall, }
path=1; { path, and erase must be }
{ different }
TYPE
regs = RECORD
al : CHAR;
ah : BYTE;
bx : INTEGER;
cx : INTEGER;
dx : INTEGER;
bp : INTEGER;
si : INTEGER;
di : INTEGER;
ds : INTEGER;
es : INTEGER;
flags : INTEGER
END;
VAR
delta_x : ARRAY [0..3] OF ARRAY [0..23] OF INTEGER;
delta_y : ARRAY [0..3] OF ARRAY [0..23] OF INTEGER;
magnitude_delta_x : INTEGER;
magnitude_delta_y : INTEGER;
num_columns : INTEGER;
num_rows : INTEGER;
register : REGS;
r_n : ARRAY [0..7] OF INTEGER;
r_n_index_1 : INTEGER;
r_n_index_2 : INTEGER;
screen : ARRAY [0..16383] OF BYTE ABSOLUTE $B800:$0000;
screen_image : ARRAY [0..16383] OF BYTE;
tem_int : INTEGER;
twice_magnitude_delta_x : INTEGER;
twice_magnitude_delta_y : INTEGER;
x : INTEGER;
x_max : INTEGER;
x_next : INTEGER;
x_out : INTEGER;
y : INTEGER;
y_max : INTEGER;
y_next : INTEGER;
y_out : INTEGER;
y_out_max : INTEGER;
PROCEDURE initialize;
VAR
delta_index_1a : INTEGER;
delta_index_1b : INTEGER;
delta_index_1c : INTEGER;
delta_index_1d : INTEGER;
delta_index_2 : INTEGER;
seed : STRING[8];
tem_int : INTEGER;
BEGIN
ClrScr;
WRITELN(OUTPUT,' Maze Generator');
WRITELN(OUTPUT,' ');
WRITELN(OUTPUT,' ');
WRITELN(OUTPUT,' ');
WRITELN(OUTPUT,
' This program will generate a maze. After the maze is generated, you');
WRITELN(OUTPUT,
'may use the cursor keys to solve it. Press Q to quit or S to have the');
WRITELN(OUTPUT,
'computer solve the maze. If the computer solves the maze, you must press');
WRITELN(OUTPUT,
'some key to exit.');
WRITELN(OUTPUT,' ');
REPEAT
WRITE(OUTPUT,' Number of columns? ');
READLN(INPUT,num_columns);
IF ((num_columns < 1) OR (num_columns > max_num_columns)) THEN
BEGIN
WRITE(OUTPUT,
'? The number of columns must be between 1 and ');
WRITE(OUTPUT,max_num_columns);
WRITELN(OUTPUT,', inclusively')
END
UNTIL ((num_columns >= 1) AND (num_columns <= max_num_columns));
WRITELN(OUTPUT,' ');
REPEAT
WRITE(OUTPUT,' Number of rows? ');
READLN(INPUT,num_rows);
IF ((num_rows < 1) OR (num_rows > max_num_rows)) THEN
BEGIN
WRITE(OUTPUT,
'? The number of rows must be between 1 and ');
WRITE(OUTPUT,max_num_rows);
WRITELN(OUTPUT,', inclusively')
END
UNTIL ((num_rows >= 1) AND (num_rows <= max_num_rows));
WRITELN(OUTPUT,' ');
WRITE(OUTPUT,' Random number seed? ');
READLN(INPUT,seed);
r_n_index_1:=0;
FOR r_n_index_2:=1 TO Length(seed) DO
BEGIN
tem_int:=ORD(seed[r_n_index_2]);
WHILE (tem_int >= 29) DO tem_int:=tem_int-29;
r_n[r_n_index_1]:=tem_int;
r_n_index_1:=r_n_index_1+1
END;
r_n_index_2:=7;
WHILE (r_n_index_1 > 0) DO
BEGIN
r_n_index_1:=r_n_index_1-1;
r_n[r_n_index_2]:=r_n[r_n_index_1];
r_n_index_2:=r_n_index_2-1
END;
WHILE (r_n_index_2 >= 0) DO
BEGIN
r_n[r_n_index_2]:=19;
r_n_index_2:=r_n_index_2-1
END;
magnitude_delta_x:=319 DIV num_columns DIV 2;
twice_magnitude_delta_x:=magnitude_delta_x+magnitude_delta_x;
magnitude_delta_y:=199 DIV num_rows DIV 2;
twice_magnitude_delta_y:=magnitude_delta_y+magnitude_delta_y;
x_max:=twice_magnitude_delta_x*num_columns;
y_max:=twice_magnitude_delta_y*num_rows;
delta_x[0][0]:=-magnitude_delta_x;
delta_y[1][0]:=magnitude_delta_y;
delta_x[2][0]:=magnitude_delta_x;
delta_y[3][0]:=-magnitude_delta_y;
delta_y[0][0]:=0;
delta_x[1][0]:=0;
delta_y[2][0]:=0;
delta_x[3][0]:=0;
delta_index_2:=-1;
FOR delta_index_1a:=0 TO 3 DO
FOR delta_index_1b:=0 TO 3 DO
IF delta_index_1a <> delta_index_1b THEN
FOR delta_index_1c:=0 TO 3 DO
IF ((delta_index_1a <> delta_index_1c)
AND (delta_index_1b <> delta_index_1c)) THEN
FOR delta_index_1d:=0 TO 3 DO
IF ((delta_index_1a <> delta_index_1d)
AND (delta_index_1b <> delta_index_1d)
AND (delta_index_1c <> delta_index_1d)) THEN
BEGIN
delta_index_2:=delta_index_2+1;
delta_x[delta_index_1a][delta_index_2]:=delta_x[0][0];
delta_y[delta_index_1a][delta_index_2]:=delta_y[0][0];
delta_x[delta_index_1b][delta_index_2]:=delta_x[1][0];
delta_y[delta_index_1b][delta_index_2]:=delta_y[1][0];
delta_x[delta_index_1c][delta_index_2]:=delta_x[2][0];
delta_y[delta_index_1c][delta_index_2]:=delta_y[2][0];
delta_x[delta_index_1d][delta_index_2]:=delta_x[3][0];
delta_y[delta_index_1d][delta_index_2]:=delta_y[3][0]
END
END;
PROCEDURE draw_horizontal(x_1,x_2,y,color : INTEGER);
VAR
bank_offset : INTEGER;
bank_segment : INTEGER;
byte_in_line : INTEGER;
byte_mask : BYTE;
color_mask : BYTE;
line_in_bank : INTEGER;
pixel_index : INTEGER;
shift_index : INTEGER;
x : INTEGER;
BEGIN
line_in_bank:=y SHR 1;
IF y = line_in_bank+line_in_bank THEN
bank_segment:=$b800
ELSE
bank_segment:=$ba00;
byte_in_line:=x_1 SHR 2;
bank_offset:=80*line_in_bank;
bank_offset:=bank_offset+byte_in_line;
pixel_index:=x_1-(byte_in_line SHL 2);
byte_mask:=3;
color_mask:=color;
shift_index:=3-pixel_index;
WHILE (shift_index > 0) DO
BEGIN
color_mask:=color_mask SHL 2;
byte_mask:=byte_mask SHL 2;
shift_index:=shift_index-1
END;
byte_mask:=NOT byte_mask;
FOR x:=x_1 TO x_2 DO
BEGIN
Mem[bank_segment:bank_offset]
:=(Mem[bank_segment:bank_offset] AND byte_mask) OR color_mask;
pixel_index:=pixel_index+1;
IF pixel_index > 3 THEN
BEGIN
pixel_index:=0;
byte_mask:=$3f;
color_mask:=color;
color_mask:=color_mask SHL 6;
bank_offset:=bank_offset+1
END
ELSE
BEGIN
byte_mask:=NOT byte_mask;
byte_mask:=byte_mask SHR 2;
byte_mask:=NOT byte_mask;
color_mask:=color_mask SHR 2
END
END
END;
PROCEDURE draw_vertical(x,y_1,y_2,color : INTEGER);
VAR
bank_1_offset : INTEGER;
bank_1_segment : INTEGER;
bank_2_offset : INTEGER;
bank_2_segment : INTEGER;
byte_in_line : INTEGER;
byte_mask : BYTE;
color_mask : BYTE;
line_in_bank : INTEGER;
offset : INTEGER;
shift_index : INTEGER;
tem_int : INTEGER;
y : INTEGER;
BEGIN
line_in_bank:=y_1 SHR 1;
IF y_1 = line_in_bank+line_in_bank THEN
BEGIN
bank_1_segment:=$b800;
bank_1_offset:=0;
bank_2_segment:=$ba00;
bank_2_offset:=0
END
ELSE
BEGIN
bank_1_segment:=$ba00;
bank_1_offset:=0;
bank_2_segment:=$b800;
bank_2_offset:=80
END;
byte_in_line:=x SHR 2;
offset:=80*line_in_bank;
offset:=offset+byte_in_line;
bank_1_offset:=bank_1_offset+offset;
bank_2_offset:=bank_2_offset+offset;
byte_mask:=$03;
color_mask:=color;
shift_index:=3;
shift_index:=shift_index-(x-(byte_in_line SHL 2));
WHILE (shift_index > 0) DO
BEGIN
color_mask:=color_mask SHL 2;
byte_mask:=byte_mask SHL 2;
shift_index:=shift_index-1
END;
byte_mask:=NOT byte_mask;
FOR y:=y_1 TO y_2 DO
BEGIN
Mem[bank_1_segment:bank_1_offset]
:=(Mem[bank_1_segment:bank_1_offset] AND byte_mask) OR color_mask;
tem_int:=bank_1_offset;
bank_1_offset:=bank_2_offset;
bank_2_offset:=tem_int+80;
tem_int:=bank_1_segment;
bank_1_segment:=bank_2_segment;
bank_2_segment:=tem_int
END
END;
FUNCTION color(x,y : INTEGER) : INTEGER;
VAR
bank_offset : INTEGER;
bank_segment : INTEGER;
byte_in_line : INTEGER;
line_in_bank : INTEGER;
byte_mask : BYTE;
shift_index : INTEGER;
BEGIN
line_in_bank:=y SHR 1;
IF y = line_in_bank+line_in_bank THEN
bank_segment:=$b800
ELSE
bank_segment:=$ba00;
byte_in_line:=x SHR 2;
bank_offset:=80*line_in_bank+byte_in_line;
shift_index:=x-(byte_in_line SHL 2);
IF shift_index < 2 THEN
IF shift_index = 0 THEN
color:=(Mem[bank_segment:bank_offset] AND $c0) SHR 6
ELSE
color:=(Mem[bank_segment:bank_offset] AND $30) SHR 4
ELSE
IF shift_index = 2 THEN
color:=(Mem[bank_segment:bank_offset] AND $0c) SHR 2
ELSE
color:=Mem[bank_segment:bank_offset] AND $03
END;
PROCEDURE add_room;
VAR
delta_index_1 : BYTE;
delta_index_2 : BYTE;
BEGIN
y_out_max:=y+magnitude_delta_y-1;
FOR y_out:=y-magnitude_delta_y+1 TO y_out_max DO
draw_horizontal(x-magnitude_delta_x+1,x+magnitude_delta_x-1,y_out,
passage);
delta_index_1:=0;
REPEAT
delta_index_2:=r_n[0];
r_n_index_1:=0;
FOR r_n_index_2:=1 TO 7 DO
BEGIN
tem_int:=r_n[r_n_index_2];
r_n[r_n_index_1]:=tem_int;
r_n_index_1:=r_n_index_1+1;
delta_index_2:=delta_index_2+tem_int;
IF delta_index_2 >= 29 THEN
delta_index_2:=delta_index_2-29
END;
r_n[7]:=delta_index_2
UNTIL (delta_index_2 < 24);
WHILE (delta_index_1 <= 3) DO
BEGIN
x_next:=x+2*delta_x[delta_index_1][delta_index_2];
IF ((x_next <= 0) OR (x_next >= x_max)) THEN
delta_index_1:=delta_index_1+1
ELSE
BEGIN
y_next:=y+2*delta_y[delta_index_1][delta_index_2];
IF ((y_next <= 0) OR (y_next >= y_max)) THEN
delta_index_1:=delta_index_1+1
ELSE
IF color(x_next,y_next) = path THEN
BEGIN
IF x = x_next THEN
draw_horizontal(x-magnitude_delta_x+1,
x+magnitude_delta_x-1,(y+y_next) DIV 2,passage)
ELSE
draw_vertical((x+x_next) DIV 2,y-magnitude_delta_y+1,
y+magnitude_delta_y-1,passage);
x:=x_next;
y:=y_next;
add_room;
x:=x-2*delta_x[delta_index_1][delta_index_2];
y:=y-2*delta_y[delta_index_1][delta_index_2]
END
ELSE
delta_index_1:=delta_index_1+1
END
END
END;
PROCEDURE generate_maze;
VAR
tem_char : BYTE;
video_offset : INTEGER;
BEGIN
GraphColorMode;
Palette(0);
tem_char:=path;
tem_char:=4*tem_char;
tem_char:=tem_char+path;
tem_char:=4*tem_char;
tem_char:=tem_char+path;
tem_char:=4*tem_char;
tem_char:=tem_char+path;
video_offset:=0;
FOR y_out:=1 TO 100 DO
FOR x_out:=1 TO 80 DO
BEGIN
Mem[$b800:video_offset]:=tem_char;
Mem[$ba00:video_offset]:=tem_char;
video_offset:=video_offset+1
END;
FOR y_out:=0 TO 199 DO
draw_horizontal(x_max+1,319,y_out,0);
FOR y_out:=y_max+1 TO 199 DO
draw_horizontal(0,319,y_out,0);
x_out:=0;
WHILE (x_out <= x_max) DO
BEGIN
draw_vertical(x_out,0,y_max,wall);
x_out:=x_out+twice_magnitude_delta_x
END;
y_out:=0;
WHILE (y_out <= y_max) DO
BEGIN
draw_horizontal(0,x_max,y_out,wall);
y_out:=y_out+twice_magnitude_delta_y
END;
IF ODD(num_columns) THEN
x:=num_columns*magnitude_delta_x
ELSE
x:=(num_columns-1)*magnitude_delta_x;
IF ODD(num_rows) THEN
y:=num_rows*magnitude_delta_y
ELSE
y:=(num_rows-1)*magnitude_delta_y;
add_room;
draw_horizontal(1,twice_magnitude_delta_x-1,0,passage);
draw_horizontal(x_max-twice_magnitude_delta_x+1,x_max,y_max,passage);
MOVE(screen,screen_image,16384);
SOUND(1000);
DELAY(333);
NOSOUND
END;
PROCEDURE let_user_try_to_solve;
VAR
delta_index_1 : INTEGER;
frequency : INTEGER;
passage_found : BOOLEAN;
tem_int : INTEGER;
BEGIN
register.ah:=8;
x:=magnitude_delta_x;
y:=magnitude_delta_y;
y_next:=0;
draw_vertical(x,0,y,path);
REPEAT
REPEAT
passage_found:=TRUE;
Intr(33,register);
IF ((register.al <> 'Q')
AND (register.al <> 'q')
AND (register.al <> 'S')
AND (register.al <> 's')) THEN
BEGIN
IF register.al = #0 THEN
BEGIN
Intr(33,register);
CASE register.al OF
#72: delta_index_1:=3;
#77: delta_index_1:=2;
#80: delta_index_1:=1;
#75: delta_index_1:=0;
ELSE
BEGIN
passage_found:=FALSE;
SOUND(120);
DELAY(278);
NOSOUND;
register.al:=' '
END
END
END
ELSE
BEGIN
CASE register.al OF
#56: delta_index_1:=3;
#54: delta_index_1:=2;
#50: delta_index_1:=1;
#52: delta_index_1:=0;
ELSE
BEGIN
passage_found:=FALSE;
SOUND(120);
DELAY(278);
NOSOUND
END
END
END;
IF passage_found THEN
BEGIN
x_next:=x+delta_x[delta_index_1][0];
y_next:=y+delta_y[delta_index_1][0];
IF color(x_next,y_next) = wall THEN
BEGIN
passage_found:=FALSE;
SOUND(120);
DELAY(278);
NOSOUND
END
ELSE
BEGIN
IF y_next = 0 THEN
BEGIN
passage_found:=FALSE;
SOUND(120);
DELAY(278);
NOSOUND
END
END
END
END
UNTIL ((passage_found)
OR (register.al = 'Q')
OR (register.al = 'q')
OR (register.al = 'S')
OR (register.al = 's'));
IF ((register.al <> 'Q')
AND (register.al <> 'q')
AND (register.al <> 'S')
AND (register.al <> 's')) THEN
BEGIN
x_next:=x_next+delta_x[delta_index_1][0];
y_next:=y_next+delta_y[delta_index_1][0];
IF y_next <= y_max THEN
BEGIN
tem_int:=color(x_next,y_next);
IF x = x_next THEN
IF y < y_next THEN
IF tem_int = path THEN
draw_vertical(x,y,y_next,erase)
ELSE
draw_vertical(x,y,y_next,path)
ELSE
IF tem_int = path THEN
draw_vertical(x,y_next,y,erase)
ELSE
draw_vertical(x,y_next,y,path)
ELSE
IF x < x_next THEN
IF tem_int = path THEN
draw_horizontal(x,x_next,y,erase)
ELSE
draw_horizontal(x,x_next,y,path)
ELSE
IF tem_int = path THEN
draw_horizontal(x_next,x,y,erase)
ELSE
draw_horizontal(x_next,x,y,path);
x:=x_next;
y:=y_next
END
END
UNTIL ((y_next > y_max)
OR (register.al = 'Q')
OR (register.al = 'q')
OR (register.al = 'S')
OR (register.al = 's'));
IF y_next > y_max THEN
BEGIN
draw_vertical(x,y,y_max,path);
frequency:=10;
FOR delta_index_1:=1 TO 100 DO
BEGIN
SOUND(frequency);
DELAY(56);
NOSOUND;
frequency:=frequency+10
END;
REPEAT
Intr(33,register);
IF ((register.al <> 'Q')
AND (register.al <> 'q')
AND (register.al <> 'S')
AND (register.al <> 's')) THEN
BEGIN
SOUND(120);
DELAY(278);
NOSOUND
END;
IF register.al = #0 THEN
BEGIN
Intr(33,register);
register.al:=' '
END
UNTIL ((register.al = 'Q')
OR (register.al = 'q')
OR (register.al = 'S')
OR (register.al = 's'))
END
END;
PROCEDURE try_adjacent_room;
VAR
delta_index_1 : BYTE;
BEGIN
delta_index_1:=0;
WHILE ((delta_index_1 <= 3) AND (y_next <= y_max)) DO
BEGIN
x_next:=x+delta_x[delta_index_1][0];
y_next:=y+delta_y[delta_index_1][0];
IF color(x_next,y_next) = passage THEN
BEGIN
x_next:=x_next+delta_x[delta_index_1][0];
y_next:=y_next+delta_y[delta_index_1][0];
IF y_next <= y_max THEN
BEGIN
IF x = x_next THEN
IF y < y_next THEN
draw_vertical(x,y,y_next,path)
ELSE
draw_vertical(x,y_next,y,path)
ELSE
IF x < x_next THEN
draw_horizontal(x,x_next,y,path)
ELSE
draw_horizontal(x_next,x,y,path);
x:=x_next;
y:=y_next;
try_adjacent_room
END;
IF y_next <= y_max THEN
BEGIN
x_next:=x;
y_next:=y;
x:=x-2*delta_x[delta_index_1][0];
y:=y-2*delta_y[delta_index_1][0];
IF x = x_next THEN
IF y < y_next THEN
draw_vertical(x,y,y_next,passage)
ELSE
draw_vertical(x,y_next,y,passage)
ELSE
IF x < x_next THEN
draw_horizontal(x,x_next,y,passage)
ELSE
draw_horizontal(x_next,x,y,passage);
delta_index_1:=delta_index_1+1
END
END
ELSE
delta_index_1:=delta_index_1+1
END
END;
PROCEDURE optionally_have_computer_solve;
VAR
tem_int : INTEGER;
BEGIN
IF ((register.al = 'S')
OR (register.al = 's')) THEN
BEGIN
MOVE(screen_image,screen,16384);
x:=magnitude_delta_x;
y:=magnitude_delta_y;
y_next:=y+magnitude_delta_y;
draw_vertical(x,0,y,path);
try_adjacent_room;
draw_vertical(x,y,y_max,path);
SOUND(1000);
DELAY(333);
NOSOUND;
register.ah:=8;
Intr(33,register);
IF register.al = #0 THEN
Intr(33,register)
END
END;
PROCEDURE terminate;
BEGIN
TextMode
END;
BEGIN
initialize;
generate_maze;
let_user_try_to_solve;
optionally_have_computer_solve;
terminate
END.